package com.game.thrones.service;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.game.thrones.constant.Errors;
import com.game.thrones.controller.input.PageInput;
import com.game.thrones.domain.KbmContent;
import com.game.thrones.domain.IdEntity.IdEntityAuto;
import com.game.thrones.exception.GameGlobalException;
import com.game.thrones.util.AutoField;
import com.game.thrones.util.BoundSql;
import com.game.thrones.util.SqlAssembleUtils;
import com.game.thrones.util.StringUtils;

@Service("baseService")
public class BaseServiceImpl<T, ID extends Serializable> implements BaseService<T, ID> {
	private Logger log = LoggerFactory.getLogger(getClass());
	@PersistenceContext
	private EntityManager entityManager;

	@Override
	@Transactional
	public void add(IdEntityAuto entity) {
		entity.setId(null);
		entityManager.persist(entity);
		entityManager.flush();
	}

	@Override
	@Transactional
	public void update(IdEntityAuto entity) {

		Set<String> set = new HashSet<String>();
		set.add("id");
		set.add("createTime");
		set.add("modifyTime");
		set.add("createId");
		set.add("modifiyId");
		// set.add("kbmContent");
		// set.add("endemicId");
		IdEntityAuto originalEntity = (IdEntityAuto) entityManager.find(getGenericType(), entity.getId());
		if (originalEntity == null) {
			throw new GameGlobalException(Errors.DELETE_ERROR);
		}
		StringUtils.copyPropertiesIgnoreNull(entity, originalEntity, set);
		entityManager.merge(originalEntity);
		entityManager.flush();
	}

	@Override
	@Transactional
	public void del(IdEntityAuto entity) {
		if (entity != null) {
			entity.setSoftDelete(1);
			entityManager.merge(entity);
			entityManager.flush();
		}
	}

	String getTableName() {
		String tableName = getGenericType().getName();
		tableName = tableName.substring(tableName.lastIndexOf(".") + 1, tableName.length() - 2);
		return StringUtils.getUnderlineName(tableName);
	}

	@Override
	public List<T> findByPage(PageInput input) {
		KbmContent kbmContent = input.getKbmContent();
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}
		List<AutoField> entityAutoField = SqlAssembleUtils.getEntityAutoField(input, AutoField.WHERE_FIELD);
		StringBuilder querySql = getWhereSql(entityAutoField, endemicId);

		if (StringUtils.isNotEmpty(input.getSortField()) && StringUtils.isNotEmpty(input.getSortOrder())) {
			querySql.append(" order by " + input.getSortField() + " " + input.getSortOrder());
		} else {
			querySql.append(" order by id desc ");
		}

		querySql.append(" limit " + (input.getPage() - 1) * input.getSize() + "," + input.getSize());
		String sql = querySql.toString();
		log.info("执行查询sql:" + sql);
		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public Integer countByPage(PageInput input) {
		KbmContent kbmContent = input.getKbmContent();
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}

		List<AutoField> entityAutoField = SqlAssembleUtils.getEntityAutoField(input, AutoField.WHERE_FIELD);
		StringBuilder querySql = getWhereSql(entityAutoField, endemicId);
		String sql = querySql.toString();
		sql = sql.replace("*", "count(*)");
		log.info("执行查询sql:" + sql);
		BigInteger result = (BigInteger) entityManager.createNativeQuery(sql).getSingleResult();
		if (result == null) {
			return 0;
		} else {
			return result.intValue();
		}
	}

	@Override
	public List<T> findAll(KbmContent kbmContent) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}

		StringBuilder querySql = getWhereSql(new ArrayList<AutoField>(), endemicId);
		String sql = querySql.toString();
		log.info("执行查询sql:" + sql);
		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public Integer countAll(KbmContent kbmContent) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}
		StringBuilder querySql = getWhereSql(new ArrayList<AutoField>(), endemicId);
		String sql = querySql.toString();
		sql = sql.replace("*", "count(*)");
		log.info("执行查询sql:" + sql);

		BigInteger result = (BigInteger) entityManager.createNativeQuery(sql).getSingleResult();
		if (result == null) {
			return 0;
		} else {
			return result.intValue();
		}
	}

	@Override
	public List<T> find(KbmContent kbmContent, Map<String, Object> param) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}

		List<AutoField> entityAutoField = SqlAssembleUtils.mapToAutoFieldList(param);
		StringBuilder querySql = getWhereSql(entityAutoField, endemicId);
		String sql = querySql.toString();
		sql+=" order by id DESC ";
		log.info("执行查询sql:" + sql);
		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public List<T> findBySql(KbmContent kbmContent, String sql) {
		if (sql == null) {
			throw new GameGlobalException(Errors.SYSTEM_ERROR);
		}
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}
		if (sql.indexOf("where") > -1) {
			sql = sql.substring(0, sql.indexOf("where") + 5) + " soft_delete=0 and endemic_id=" + endemicId + " and "
					+ sql.substring(sql.indexOf("where") + 5);
		} else {
			sql += " where soft_delete=0 and endemic_id=" + endemicId;
		}

		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

	@Override
	public List<Object> findListBySql(KbmContent kbmContent, String sql) {
		if (sql == null) {
			throw new GameGlobalException(Errors.SYSTEM_ERROR);
		}
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}
		if (sql.indexOf("where") > -1) {
			sql = sql.substring(0, sql.indexOf("where") + 5) + " soft_delete=0 and endemic_id=" + endemicId + " and "
					+ sql.substring(sql.indexOf("where") + 5);
		} else {
			sql += " where soft_delete=0 and endemic_id=" + endemicId;
		}
		return (List<Object>) entityManager.createNativeQuery(sql).getResultList();
	}

	@Override
	public Integer count(KbmContent kbmContent, Map<String, Object> param) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}

		List<AutoField> entityAutoField = SqlAssembleUtils.mapToAutoFieldList(param);
		StringBuilder querySql = getWhereSql(entityAutoField, endemicId);
		String sql = querySql.toString();
		sql = sql.replace("*", "count(*)");
		log.info("执行查询sql:" + sql);
		BigInteger result = (BigInteger) entityManager.createNativeQuery(sql).getSingleResult();
		if (result == null) {
			return 0;
		} else {
			return result.intValue();
		}
	}

	@Override
	public Integer count(KbmContent kbmContent, String sql) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}

		if (sql.indexOf("count") == -1) {
			sql = sql.replace("*", "count(*)");
		}
		if (sql.indexOf("where") > -1) {
			sql = sql.substring(0, sql.indexOf("where") + 5) + " soft_delete=0 and endemic_id=" + endemicId + " and "
					+ sql.substring(sql.indexOf("where") + 5);
		} else {
			sql += " where soft_delete=0 and endemic_id=" + endemicId;
		}
		log.info("执行查询sql:" + sql);
		BigInteger result = (BigInteger) entityManager.createNativeQuery(sql).getSingleResult();
		if (result == null) {
			return 0;
		} else {
			return result.intValue();
		}
	}

	@Override
	public T findOne(KbmContent kbmContent, Map<String, Object> param) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}

		List<AutoField> entityAutoField = SqlAssembleUtils.mapToAutoFieldList(param);
		StringBuilder querySql = getWhereSql(entityAutoField, endemicId);
		querySql.append(" limit 0,1");
		String sql = querySql.toString();
		log.info("执行分页查询sql:" + sql);
		try {
			return (T) entityManager.createNativeQuery(sql, getGenericType()).getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}

	@Override
	public T findOne(KbmContent kbmContent, Object input) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}

		List<AutoField> entityAutoField = SqlAssembleUtils.getEntityAutoField(input, AutoField.WHERE_FIELD);
		StringBuilder querySql = getWhereSql(entityAutoField, endemicId);
		querySql.append(" limit 0,1");
		String sql = querySql.toString();
		log.info("执行查询sql:" + sql);
		try {
			return (T) entityManager.createNativeQuery(sql, getGenericType()).getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}

	@Override
	public T findOneBySql(KbmContent kbmContent, String sql) {
		if (sql == null) {
			throw new GameGlobalException(Errors.SYSTEM_ERROR);
		}
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}
		if (sql.indexOf("where") > -1) {
			sql = sql.substring(0, sql.indexOf("where") + 5) + " soft_delete=0 and endemic_id=" + endemicId + " and "
					+ sql.substring(sql.indexOf("where") + 5);
		} else {
			sql += " where soft_delete=0 and endemic_id=" + endemicId;
		}
		sql += " limit 0,1";
		log.info("执行查询sql:" + sql);
		try {
			return (T) entityManager.createNativeQuery(sql, getGenericType()).getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}

	@Override
	public T findOneById(KbmContent kbmContent, Integer id) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}
		if (id == null) {
			return null;
		}
		List<AutoField> entityAutoField = new ArrayList<AutoField>();
		{// 设置id查询值
			AutoField autoField = new AutoField();
			autoField.setName("id");
			autoField.setSqlOperator("and");
			autoField.setFieldOperator("=");
			autoField.setValues(new Object[] { id });
			autoField.setType(AutoField.WHERE_FIELD);
			entityAutoField.add(autoField);
		}
		StringBuilder querySql = getWhereSql(entityAutoField, endemicId);
		querySql.append(" limit 0,1");
		String sql = querySql.toString();
		log.info("执行分页查询sql:" + sql);
		try {
			return (T) entityManager.createNativeQuery(sql, getGenericType()).getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}

	/**
	 * 根据AutoField 的list生成where sql语句
	 * 
	 * @param entityAutoField
	 * @param endemicId
	 * @return
	 */
	private StringBuilder getWhereSql(List<AutoField> entityAutoField, Integer endemicId) {
		String columns = "*";
		StringBuilder querySql = new StringBuilder("SELECT " + columns + " FROM ");
		querySql.append(getTableName());
		querySql.append(" WHERE ");
		querySql.append(" soft_delete=0 ");
		if (endemicId != -1) {// 如果地方中心为-1表示不做地方中心过滤
			querySql.append(" and endemic_id=" + endemicId);
		}
		if (entityAutoField.size() > 0) {
			BoundSql boundSql = SqlAssembleUtils.builderWhereSql(entityAutoField);
			if (boundSql.getParams().size() > 0) {
				querySql.append(" and " + boundSql.getSql());
			}
		}
		return querySql;
	}

	private Class getGenericType() {
		Type genType = getClass().getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		if (params.length < 0) {
			throw new RuntimeException("Index outof bounds");
		}
		if (!(params[0] instanceof Class)) {
			return Object.class;
		}
		return (Class) params[0];
	}

	@Override
	public List<T> find(KbmContent kbmContent, Object input) {
		if (kbmContent == null) {
			throw new GameGlobalException(Errors.LACK_CONTENT);
		}
		if (kbmContent.getCurrentUserId() == null) {
			throw new GameGlobalException(Errors.NOT_LOGIN);
		}
		Integer endemicId = kbmContent.getEndemicId();
		if (endemicId == null) {
			throw new GameGlobalException(Errors.NO_ENDEMIC);
		}

		List<AutoField> entityAutoField = SqlAssembleUtils.getEntityAutoField(input, AutoField.WHERE_FIELD);
		StringBuilder querySql = getWhereSql(entityAutoField, endemicId);
		String sql = querySql.toString();
		log.info("执行查询sql:" + sql);

		return entityManager.createNativeQuery(sql, getGenericType()).getResultList();
	}

}
